package com.sl.core.engine.log.store;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.sl.core.engine.log.store.domain.entity.LogDetailDO;
import com.sl.core.engine.log.store.domain.entity.MainLogDO;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.persistence.Id;
import jakarta.persistence.Lob;
import lombok.SneakyThrows;
import org.anyline.data.jdbc.runtime.JDBCRuntimeHolder;
import org.anyline.data.jdbc.util.DataSourceUtil;
import org.anyline.data.runtime.RuntimeHolder;
import org.anyline.entity.DataRow;
import org.anyline.metadata.Column;
import org.anyline.metadata.Table;
import org.anyline.metadata.type.init.StandardTypeMetadata;
import org.anyline.proxy.ServiceProxy;
import org.anyline.service.AnylineService;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Map;

public abstract class AbstractDbLogStore implements IProcessLogStore {


    @SneakyThrows
    protected AnylineService initDb() {
        String jdbcUrl = getJdbcUrl();
        AnylineService anylineService = initDb(jdbcUrl);
        return anylineService;
    }

    @Override
    public Boolean saveDetail(LogDetailDO logDetailDO) {
        logDetailDO.setCreateTime(DateUtil.date());
        AnylineService logDetailTable = createLogDetailTable();
        //存储到数据库中
        DataRow dataRow = DataRow.parse(logDetailDO);
        logDetailTable.insert(getTableName(LogDetailDO.class), dataRow);
        return Boolean.TRUE;
    }


    @Override
    public Boolean startMain(MainLogDO mainLogDO) {
        mainLogDO.setState(0);
        mainLogDO.setCreateTime(new Date());
        AnylineService mainTable = createMainTable();

        String tableName = getTableName(MainLogDO.class);
        DataRow query = mainTable.query(tableName, "tid = '" + mainLogDO.getTid() + "'");
        if(ObjectUtil.isNotNull(query)){
            return Boolean.FALSE;
        }
        //存储到数据库中
        DataRow dataRow = DataRow.parse(mainLogDO);


        mainTable.insert(getTableName(MainLogDO.class), dataRow);
        return Boolean.TRUE;
    }

    @SneakyThrows
    @Override
    public Boolean finishMain(String tid, Date endTime, Integer state) {

        AnylineService anylineService = initDb();

        String tableName = getTableName(MainLogDO.class);
        DataRow query = anylineService.query(tableName, "tid = '" + tid + "'");
        if (ObjectUtil.isNull(query)) {
            return null;
        }

        MainLogDO mainLogDO = new MainLogDO();
        mainLogDO.setState(state);
        mainLogDO.setId(query.getLong("id"));

        Date startDate = query.getDate("startTime");

        if (ObjectUtil.isAllNotEmpty(startDate, endTime)) {
            long cost = DateUtil.betweenMs(startDate, endTime);
            mainLogDO.setCost(cost);
        }
        mainLogDO.setEndTime(endTime);
        DataRow dataRow = DataRow.parse(mainLogDO);
        anylineService.update(tableName, dataRow);

        return Boolean.TRUE;
    }

    @Override
    public Boolean updateStateById(String id, Integer state) {
        AnylineService anylineService = initDb();

        String tableName = getTableName(MainLogDO.class);
        DataRow query = anylineService.query(tableName, "id = '" + id + "'");
        if (ObjectUtil.isNull(query)) {
            return null;
        }

        MainLogDO mainLogDO = new MainLogDO();
        mainLogDO.setState(state);
        mainLogDO.setId(query.getLong("id"));
        DataRow dataRow = DataRow.parse(mainLogDO);
        anylineService.update(tableName, dataRow);
        return Boolean.TRUE;
    }

    protected AnylineService initDb(String jdbcUrl) {
        return initDb(jdbcUrl, getJdbcDriver(), getJdbcUserName(), getJdbcPassword());
    }

    protected AnylineService initDb(String jdbcUrl, String jdbcDriver, String jdbcUserName, String jdbcPassword) {
        if(StrUtil.isBlank(jdbcUrl)){
            return null;
        }
        String encode = Base64.encode(jdbcUrl);
        if (RuntimeHolder.contains(encode)) {
            return ServiceProxy.service(encode);
        }
        synchronized (this) {
            if (RuntimeHolder.contains(encode)) {
                return ServiceProxy.service(encode);
            }
            DataSource dataSource = getDataSource(jdbcUrl, jdbcDriver, jdbcUserName, jdbcPassword);
            if (!RuntimeHolder.contains(encode)) {
                JDBCRuntimeHolder.instance().reg(encode, dataSource);
            }
            AnylineService anylineService = ServiceProxy.service(encode);
            return anylineService;
        }
    }

    protected DataSource getDataSource(String jdbcUrl, String jdbcDriver, String jdbcUserName, String jdbcPassword) {
        Map<String, Object> maps = Maps.newConcurrentMap();
        maps.put("url", jdbcUrl);
        maps.put("driver", jdbcDriver);
        maps.put("username", jdbcUserName);
        maps.put("password", jdbcPassword);
        maps.put("type", HikariDataSource.class.getName());
        DataSource dataSource = DataSourceUtil.build(maps);
        return dataSource;
    }


    @SneakyThrows
    private AnylineService createMainTable() {
        return createTable(MainLogDO.class);
    }


    @SneakyThrows
    private AnylineService createLogDetailTable() {
        AnylineService table = createTable(LogDetailDO.class);
        return table;
    }

    public String getTableName(Class<?> clazz) {
        jakarta.persistence.Table annotation = AnnotationUtil.getAnnotation(clazz, jakarta.persistence.Table.class);
        return annotation.name();
    }

    @SneakyThrows
    private AnylineService createTable(Class<?> clazz) {
        AnylineService anylineService = initDb();
        Table table = new Table(getTableName(clazz));

        boolean exists = anylineService.metadata().exists(table);
        //存在就不管了
        if (BooleanUtil.isTrue(exists)) {
            return anylineService;
        }
        Field[] fields = ReflectUtil.getFields(clazz);

        for (Field field : fields) {
            String name = field.getName();
            Class<?> type = field.getType();
            Column column = new Column(name);


            Id antoId = AnnotationUtil.getAnnotation(field, Id.class);
            if (ObjectUtil.isNotNull(antoId)) {
                column.setTypeMetadata(StandardTypeMetadata.BIGINT);
                column.autoIncrement(true);
                column.setPrimaryKey(true);
            } else {

                Lob lob = AnnotationUtil.getAnnotation(field, Lob.class);

                if (type.equals(Date.class)) {
                    column.setTypeMetadata(StandardTypeMetadata.DATETIME);
                } else if (type.equals(Integer.class)) {
                    column.setTypeMetadata(StandardTypeMetadata.INTEGER);
                } else if (type.equals(Long.class)) {
                    column.setTypeMetadata(StandardTypeMetadata.LONG);
                } else {
                    if (ObjectUtil.isNotNull(lob)) {
                        column.setTypeMetadata(StandardTypeMetadata.TEXT);
                    } else {
                        column.setTypeMetadata(StandardTypeMetadata.VARCHAR);
                        column.setLength(250);
                    }
                }
            }
            table.addColumn(column);
        }
        //没有就创建
        anylineService.ddl().create(table);
        return anylineService;
    }



    abstract protected String getJdbcUserName();

    abstract protected String getJdbcPassword();

    abstract protected String getJdbcUrl();

    abstract protected String getJdbcDriver();

}
